import hashlib
import json
import re
import time
from aiohttp import web
from base import Dict
from config.config_util import config
import dao
from domain import User, Role, Privilege
from FrontUtils import user2cookie
from exception import PrivilegeError

__author__ = 'thanatos'

from handlers import get, post, permission


@get('/victoria')
def index():
    blogs = [
        {'title': 'Bootstrap大法好啊', 'create_at': time.time() - 3600},
        {'title': 'Python是一门高效又优雅的语言', 'create_at': time.time() - 60},
        {'title': 'Java适合去开发企业级的应用', 'create_at': time.time() - 360460},
        {'title': '挖掘机学校哪家强！', 'create_at': time.time() - 8000},
        {'title': '机器学习与数据挖掘', 'create_at': time.time() - 4000}
    ]
    return {
        '__template__': 'victoria.html',
        'blogs': blogs
    }

@get('/')
def admin_index():
    return 'redirect:/static/tpls/admin/adminIndex.html'

@get('/register')
def register():
    return {
        '__template__': 'register.html'
    }

@get('/favicon.ico')
def favicon():
    return 'redirect:/static/favicon.ico'

_RE_EMAIL = re.compile(r'^[a-z0-9\.\-\_]+\@[a-z0-9\-\_]+(\.[a-z0-9\-\_]+){1,4}$')
COOKIE_NAME = config.cookie.name


@post('/register')
def register(*, name, email, password, request):
    errors = Dict()
    if not name or len(name) > 10:
        errors.name = '昵称填写有误'
    if not email or not _RE_EMAIL.match(email):
        errors.email = '邮箱填写错误'
    if not password:
        errors.password = '密码不能为空'
    users = yield from User.findAll('email=?', [email])
    if len(users) > 0:
        errors.user = '用户已注册'
    if errors:
        return {
            '__template__': 'register.html',
            'errors': errors
        }
    password = hashlib.md5(password.encode('utf-8')).hexdigest()
    user = User(name=name, email=email, password=password)
    yield from user.save()
    # make session cookie:
    r = web.Response()
    r.set_cookie(COOKIE_NAME, user2cookie(user, 86400), max_age=86400, httponly=True)
    referer = request.headers.get('Referer')
    r = web.HTTPFound(referer or '/')
    return r


@get('/login')
def login():
    return {
        '__template__': 'login.html'
    }


@post('/login')
def login(*, name, password, request):
    if not name or not password:
        return {
            'code': 1,
            'message': '邮箱或密码不能为空'
        }
    users = yield from User.findAll(name, where='name=?')
    if not users:
        return {
            'code': 1,
            'message': '没有此用户'
        }
    user = users[0]
    if user.password != hashlib.md5(password.encode('utf-8')).hexdigest():
        return {
            'code': 1,
            'message': '帐号或密码错误'
        }
    # authenticate ok, set cookie:
    r = web.Response(body=json.dumps({'code': 0}, ensure_ascii=False, default=lambda o: o.__dict__, allow_nan=False).encode('utf-8'))
    r.content_type = 'application/json;charset=utf-8'
    r.set_cookie(COOKIE_NAME, user2cookie(user, 86400), max_age=86400, httponly=True)
    return r


@get('/login_out')
def login_out():
    web.Response.set_cookie(COOKIE_NAME, '-deleted-', max_age=0, httponly=True)
    return {
        'code': 0
    }

@get('/admin/user/list')
@permission('admin:user.list')
def user_list(*, request, is_admin=False, current=1):
    """
    User列表
    :param is_admin: True查找admin用户列表，False查找非admin用户列表
    :return:
    """
    page = yield from User.page(current=current, cascade=True)
    if page.data:
        for user in page.data:
            user.remove('password', 'isAdmin')
            if user.roles:
                for role in user.roles:
                    role.reserve('id', 'name')
    return {
        'code': 0,
        'page': page
    }

@get('/admin/user/unique')
@permission('admin:user.unique')
def user_unique(*,request, uid):
    """
    根据用户id查找用户
    :param uid:
    :return:
    """
    user = yield from User.find(uid, fetchable=False, cascade=True)
    user.remove('password')
    return {
        'code': 0,
        'user': user
    }



@post('/admin/user/add')
@permission('admin:user.add')
def user_add(*, request, user=User, rids=None):
    """
    User添加
    :param user:
    :return:
    """
    user.password = hashlib.md5(user.password.encode('utf-8')).hexdigest()
    yield from user.save()
    if rids:
        for rid in rids:
            yield from dao.execute('INSERT INTO User_Role(user_id, role_id) VALUES(?,?)', (user.id, rid))
    print('user add --> %s ' % user)
    return {
        'code': 0,
        'message': '添加成功'
    }


@post('/admin/role/add')
@permission('admin:role.add')
def role_add(*, request, role=Role):
    """
    Role添加
    :param role:
    :return:
    """
    yield from role.save()
    return {
        'code': 0,
        'message': '添加成功'
    }


@post('/admin/privilege/add')
@permission('admin:privilege.add')
def privilege_add(*, request, privilege=Privilege, parent_id=None):
    """
    Privilege添加
    :param privilege:
    :return:
    """
    privilege.parent = parent_id
    yield from privilege.save()
    return {
        'code': 0,
        'message': '添加成功'
    }


@post('/admin/{model}/delete')
def model_delete(*, model, uid, request):
    """
    User, Role, Privilege的删除操作
    :param model: 由URL决定操作的对象
    :param uid: 传JSON格式的数组
    :return:
    """
    if not uid:
        return {
            'code': 1,
            'message': '没有id值'
        }
    if model == 'user':
        if not request.__user__.access('admin:user.delete'):
            raise PrivilegeError()
        user = User(id=uid)
        yield from dao.execute('DELETE FROM User_Role WHERE user_id=?', user.id)
        yield from user.prune()
    if model == 'role':
        if not request.__user__.access('admin:role.delete'):
            raise PrivilegeError()
        role = Role(id=uid)
        yield from dao.execute('DELETE FROM User_Role WHERE role_id=?', role.id)
        yield from dao.execute('DELETE FROM Role_Privilege WHERE role_id=?', role.id)
        yield from role.prune()
    if model == 'privilege':
        if not request.__user__.access('admin:privilege.delete'):
            raise PrivilegeError()
        privilege = Privilege(id=uid)
        yield from dao.execute('DELETE FROM Role_Privilege WHERE privilege_id=?', privilege.id)
        yield from privilege.prune()
    return {
        'code': 0
    }


@post('/admin/user/update')
@permission('admin:user.update')
def user_update(*, request, user=User, rids):
    """
    用户信息更新
    :param user: name, email, telephone, role
    :param rids:
    :return:
    """
    if user.id is None:
        return {
            'code': 1
        }
    yield from user.renew('name', 'email', 'telephone')
    yield from dao.execute('DELETE FROM User_Role WHERE user_id=?', user.id)
    if rids is not None and rids:
        for rid in rids:
            yield from dao.execute('INSERT INTO User_Role(user_id, role_id) VALUES(?,?)', (user.id, rid))
    return {
        'code': 0,
        'message': '更新成功'
    }

@post('/admin/role/update')
@permission('admin:role.update')
def role_update(*, request, role=Role, pids):
    """
    更新角色信息
    :param role:
    :param pids:
    :return:
    """
    if role.id is None:
        return {
            'code': 1
        }
    yield from role.renew('name', 'description')
    yield from dao.execute('DELETE FROM Role_Privilege WHERE role_id=?', role.id)
    if pids is not None and pids:
        for pid in pids:
            yield from dao.execute('INSERT INTO Role_Privilege(role_id, privilege_id) VALUES(?,?)', (role.id, pid))
    return {
        'code': 0,
        'message': '更新成功'
    }


@get('/admin/role/list')
@permission('admin:role.list')
def role_list(*, request, page_num=1):
    """
    角色列表
    :param page_num:
    :return:
    """
    page = yield from Role.page(current=page_num)
    return {
        'code': 0,
        'page': page
    }

@get('/admin/role/unique')
@permission('admin:role.unique')
def role_unique(*, request, rid):
    """
    得到这个角色对象以及它所有的权限
    :param rid:
    :return:
    """
    role = yield from Role.find(rid)
    sqls = ['SELECT p.* FROM Role_Privilege AS rp',
            'JOIN Privilege AS p',
            'ON p.id = rp.privilege_id AND rp.role_id=?']
    privileges = yield from Privilege.select(role.id, sql=' '.join(sqls + ['AND p.parent_id IS NULL']))

    def find_children(ps):
        for p in ps:
            children = yield from Privilege.select(role.id, p.id, sql=' '.join(sqls + ['AND p.parent_id=?']))
            if children:
                p.children = children
                yield from find_children(children)
    if privileges:
        yield from find_children(privileges)
        role.privileges = privileges
    return {
        'code': 0,
        'role': role
    }


@get('/admin/role/simple/list')
@permission('admin:role.simple-list')
def role_simple_list(*, request):
    """
    角色下拉菜单，只返回所有Role的id,name
    :return:
    """
    roles = yield from Role.select(sql='SELECT id,name FROM Role')
    return {
        'code': 0,
        'roles': roles
    }


@get('/admin/privilege/list')
@permission('admin:privilege.list')
def privilege_list(*, request):
    """
    Privilege列表
    :return:
    """
    privileges = yield from Privilege.findAll(where='parent_id IS NULL', fetchable=False)
    yield from Privilege.find_children(privileges)
    return {
        'code': 0,
        'privileges': privileges
    }

@get('/admin/privilege/unique')
@permission('admin:privilege.unique')
def privilege_unique(*, request, pid):
    """
    得到单个权限对象以及他的全部子权限
    :param pid:
    :return:
    """
    privilege = yield from Privilege.find(pid, fetchable=True)
    yield from Privilege.find_children(privilege)
    return {
        'code': 0,
        'privilege': privilege
    }

@post('/admin/privilege/update')
@permission('admin:privilege.update')
def privilege_update(*, request, privilege=Privilege):
    """
    更新权限信息
    :param privilege:
    :return:
    """
    if privilege[Privilege.__key__] is None:
        return {
            'code': 1
        }
    yield from privilege.renew()
    return {
        'code': 0,
        'message': '更新成功'
    }

@post('/admin/{model}/batch/delete')
def batch_delete(*, request, model, ids):
    """
    User,Role,Privilege批量删除
    :param model: 由URL决定，user,role,privilege
    :param ids: 传JSON格式的数组
    :return:
    """
    if isinstance(ids, list):
        for uid in ids:
            yield from model_delete(model=model, uid=uid, request=request)
        return {
            'code': 0,
            'message': '删除成功'
        }
    else:
        return {
            'code': 1
        }


@post('/admin/user/add/role')
@permission('admin:user.add-role')
def user_add_role(*, request, uid, rids):
    """
    为用户添加角色
    :param uid: 用户id
    :param rids: 角色id
    :return:
    """
    if uid and rids:
        for rid in rids:
            yield from dao.execute('INSERT INTO User_Role(user_id, role_id) VALUES(?,?)', uid, rid)
    return {
        'code': 0,
        'message': '添加成功'
    }


@post('/admin/role/add/privilege')
@permission('admin:role.add-privilege')
def role_add_privilege(*, request, rid, pids):
    """
    为角色添加权限
    :param rid: 角色id
    :param pids: 权限id
    :return:
    """
    if rid and pids:
        for pid in pids:
            yield from dao.execute('INSERT INTO Role_Privilege(role_id, privilege_id) VALUES(?,?)', (rid, pid))
    return {
        'code': 0,
        'message': '添加成功'
    }


@get('/admin/user/get/privilege')
def user_get_privilege(*, request):
    """
    用户获得自己可使用权限
    :return:
    """
    sqls = ['SELECT privilege_id AS id, privilege_name AS name, privilege_url AS url',
            'FROM User_Role_Privilege WHERE privilege_is_display=1 AND user_id=?']
    privileges = yield from dao.select(' '.join(sqls + ['AND privilege_parent_id IS NULL']), request.__user__.id)

    privileges = yield from Privilege.transfer(privileges, False, False)

    def find_children(ps):
        for p in ps:
            children = yield from Privilege.select(request.__user__.id, p.id, sql=' '.join(sqls + ['AND privilege_parent_id=?']))
            if children:
                p.children = children
                yield from find_children(children)
    if privileges:
        yield from find_children(privileges)
    return {
        'code': 0,
        'privileges': privileges
    }
